#pragma once
#include<iostream>
#include<vector>
#include<set>
#include<map>
using namespace std;

class LocInfo{
private:
    int16_t blockNo;
    int ind;

    void init(const int16_t& blockNo, const int& ind){
        this->blockNo = blockNo;
        this->ind = ind;
    }

public:

    LocInfo(){}

    LocInfo(const LocInfo& locInfo){
        init(locInfo.blockNo, locInfo.ind);
    }

    LocInfo(const LocInfo* locInfo){
        init(locInfo->blockNo, locInfo->ind);
    }

    LocInfo(const int16_t& blockNo, const int& ind){
        init(blockNo, ind);
    }

    LocInfo(const char* byteData){
        memcpy(&blockNo, &byteData[0], sizeof (blockNo));
        memcpy(&ind, &byteData[sizeof (blockNo)], sizeof (ind));
    }

    bool operator == (const LocInfo& locInfo) const {
        return this->blockNo == locInfo.blockNo && this->ind == locInfo.ind;
    }

    bool operator < (const LocInfo& locInfo) const {
        const int16_t& blockNo1 = this->blockNo, blockNo2 = locInfo.blockNo;
        if(blockNo1 != blockNo2){
            return blockNo1 < blockNo2;
        }
        return this->ind < locInfo.ind;
    }

    int getBlockNo() const {
        return blockNo;
    }

    int getInd() const {
        return ind;
    }

    static int getLocInfoSize(){
        return sizeof (blockNo) + sizeof (ind);
    }

    static vector<int> getEachEleSize(){
        return {sizeof (blockNo), sizeof (ind)};
    }
};



bool locInfoCmp(const LocInfo& locInfo1, const LocInfo& locInfo2){
    const int16_t& blockNo1 = locInfo1.getBlockNo(), blockNo2 = locInfo2.getBlockNo();
    if(blockNo1 != blockNo2){
        return blockNo1 < blockNo2;
    }
    return locInfo1.getInd() < locInfo2.getInd();
}


class LocInfoUtil{
public:

    static vector<LocInfo> mergeSortLocInfoToLocInfo(const map<int16_t, set<int>>& mergeSortLocInfo){
        vector<LocInfo> locInfoVec;
        for(const auto& it : mergeSortLocInfo){
            const int16_t& blockNo = it.first;
            for(const int& ind : it.second){
                locInfoVec.push_back(LocInfo(blockNo, ind));
            }
        }
        return locInfoVec;
    }

    static map<int16_t, set<int>> locInfoToMergeSortLocInfo(const vector<LocInfo>& locInfoVec){
        map<int16_t, set<int>> mergeSortLocInfo;
        for(const LocInfo& locInfo : locInfoVec){
            mergeSortLocInfo[locInfo.getBlockNo()].insert(locInfo.getInd());
        }
        return mergeSortLocInfo;
    }

    static void insertMergeSortLocInfo(map<int16_t, set<int>>& totalMergeSortLocInfo, const map<int16_t, set<int>>& mergeSortLocInfo){
        for(const auto& it : mergeSortLocInfo){
            const set<int>& sortIndVec = it.second;
            totalMergeSortLocInfo[it.first].insert(sortIndVec.begin(), sortIndVec.end());
        }
    }

    static void insertMergeSortLocInfo(map<int16_t, set<int>>& totalMergeSortLocInfo, const vector<LocInfo*>& locInfoVec){
        for(const LocInfo* locInfo : locInfoVec){
            totalMergeSortLocInfo[locInfo->getBlockNo()].insert(locInfo->getInd());
        }
    }
};
